package com.api.apiclientsdk.client;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import com.api.apiclientsdk.model.InterfaceInfoInvokeParams;
import com.api.apiclientsdk.model.enums.APIConstant;

import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import static com.api.apiclientsdk.utils.SignUtils.genSign;


/**
 * 调用第三方接口的客户端
 *
 * @author <a href="https://github.com/licui">程序员鱼皮</a>
 * @from <a href="https://cui.icu">编程导航知识星球</a>
 */
public class ApiClient {


    public String request(InterfaceInfoInvokeParams interfaceInfoInvokeParams){
     String url = interfaceInfoInvokeParams.getUrl();
     String method = interfaceInfoInvokeParams.getMethod();
     String params = interfaceInfoInvokeParams.getParams();
     String accessKey = interfaceInfoInvokeParams.getAccessKey();
     String secretKey = interfaceInfoInvokeParams.getSecretKey();
        return request(url,method,params,accessKey,secretKey);
    }
    public String request(String url, String method, String params, String accessKey, String secretKey) {
        // 参数检查
        validateParams(url, method, params, accessKey, secretKey);

        // 请求参数处理
        String body = URLUtil.decode(params.trim(), CharsetUtil.CHARSET_UTF_8);
        Map<String, Object> paramMap = JSONUtil.toBean(body, Map.class);

        // 构建请求头
        Map<String, String> headers = createHeaderMap(params, accessKey, secretKey);

        // 执行请求
        return executeRequest(url, method, paramMap, body, headers);
    }

    // 执行 HTTP 请求
    private String executeRequest(String url, String method, Map<String, Object> paramMap, String body, Map<String, String> headers) {
        HttpResponse response;
        try {
//            logger.info("发送请求: url={}, method={}, params={}", url, method, paramMap);
            if (APIConstant.GET.getValue().equalsIgnoreCase(method)) {
                response = HttpRequest.get(url)
                        .addHeaders(headers)
                        .form(paramMap)
                        .execute();
            } else if (APIConstant.POST.getValue().equalsIgnoreCase(method)) {
                response = HttpRequest.post(url)
                        .addHeaders(headers)
                        .body(body)
                        .execute();
            } else {
                throw new IllegalArgumentException("不支持的请求方法: " + method);
            }
//            logger.info("请求响应: status={}, body={}", response.getStatus(), response.body());
            return response.body();
        } catch (Exception e) {
//            logger.error("请求失败: {}", e.getMessage());
            throw new RuntimeException("请求失败: " + e.getMessage(), e);
        }
    }

    // 构建请求头
    //需要获取用户传递的 accessKey 和 secretKey。对于这种数据，建议不要直接在 URL 中传递，而是选择在请求头中传递会更为妥当。
    // 因为 GET 请求的 URL 存在最大长度‍限制，如果你传递的其他参数过多，可能会导致关键数据被挤出。因此，建议从请求头中获取这些数据。
    private Map<String, String> createHeaderMap(String params, String accessKey, String secretKey) {
        Map<String, String> headers = new HashMap<>();
        headers.put("accessKey", accessKey);
        //防重放 加 nonce 随机数，只能用一次
        headers.put("nonce", RandomUtil.randomNumbers(16));
        headers.put("body", params);
        //加 timestamp 时间戳，校验时间戳是否过期。
        // System.currentTimeMillis()返回当前时间的毫秒数。通过除以1000，可以将毫秒数转换为秒数，以得到当前时间戳的秒级表示
        // String.valueOf()方法用于将数值转换为字符串。在这里，将计算得到的时间戳（以秒为单位）转换为字符串
        headers.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
        /**
         * 在向对方发送请求时，密码绝对不能以明文的方式传递，必须通过特殊的方式进行传递
         * 绝对不能直接在服务端或服务器之间传递密钥，这样是不安全的
         * 在标准的 API 签名认证中，我们需要传递一个签名
         * 通常我们不是直接将其传递给后台，而是根据该密钥生成一个签名。因为密码不能直接在服务器中传递，有可能会被拦截。
         * 在向对方发送请求时，密码绝对不能以明文的方式传递，必须通过特殊的方式进行传递
         */
        //用户参数 + 密钥 => 签名生成算法（MD5、HMac、Sha1） => 不可解密的值
        headers.put("sign", genSign(params, secretKey));
        return headers;
    }

    // 校验参数
    private void validateParams(String url, String method, String params, String accessKey, String secretKey) {
        if (StrUtil.isBlank(url) || StrUtil.isBlank(method) || StrUtil.isBlank(params)
                || StrUtil.isBlank(accessKey) || StrUtil.isBlank(secretKey)) {
            throw new RuntimeException("参数不能为空");
        }
        try {
            new URL(url);
        } catch (Exception e) {
            throw new RuntimeException("接口地址错误");
        }
    }


    @Deprecated
    public String requestOld(String url, String method, String params, String accessKey, String secretKey) {
        if (StrUtil.isBlank(url) || StrUtil.isBlank(method) || StrUtil.isBlank(params) || StrUtil.isBlank(accessKey)
                || StrUtil.isBlank(secretKey)) {
            throw new RuntimeException("参数不能为空");
        }

        String body = URLUtil.decode(params.trim(), CharsetUtil.CHARSET_UTF_8);
        String result = "";
        if (APIConstant.GET.getValue().equals(method)) {
             Map<String,Object> bean = JSONUtil.toBean(body, Map.class);
            try (HttpResponse response = HttpRequest.get(url + "?" + body)
                    .form(bean)
                    .addHeaders(createHeaderMap(params, accessKey, secretKey))
                    .execute()) {
                result = response.body();
            }
        } else if (APIConstant.POST.getValue().equals(method)) {
            try (HttpResponse response = HttpRequest.post(url)
                    .addHeaders(createHeaderMap(params, accessKey, secretKey))
                    .form(body)
                    .body(body)
                    .execute()) {
                result = response.body();
            }
        }
        return result;

    }


}
